package sudoku_gui;

import sudoku_gui_handler.DnDHandler;
import sudoku_gui_handler.SpinnerHandler;
import database_handler.DatabaseManager;
import database_handler.DatabaseParam;
import its_models.student_model.StudentModelProperties;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import help_util.IndexConverter;
import its_models.expert_model.expert_help_util.StrategyGraphUnit;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.JCheckBox;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import model_controller.ControlLayer;
import sudoku_gameboard_structure.SudokuGameboard;
import sudoku_gui_handler.TimerHandler;
import sudoku_properties.AlertBoxParam;
import sudoku_properties.BasicSudokuParam;
import sudoku_properties.SudokuGameInfoParam;

/******************************************************
 * Class WebSudokuApplet                             **
 * 1. Design the interface of the applet             **
 * 2. SetupUI components for the Applet              **
 *****************************************************/
public class WebSudokuApplet extends JApplet{

    /* get input param */
    @Override
    public void init(){
       /*Commnet line if run alone, otherwise screen not shown */
       String parameter1Name = "userID";
       String parameter2Name = "langMode";
       UserID = Integer.parseInt(getParameter(parameter1Name));
       LangMode = Integer.parseInt(getParameter(parameter2Name));
       //UserID = 0;
       //LangMode = 0;
       WebSudokuApplet();
       //
       //Controller.setTextLearnerStepsMsgBox("\nUser Id = " + USER_ID+"\n\n");
    }

    public void WebSudokuApplet(){
        initComponents();
        setupUI();
        setupITSModels();
        setupDBManager();
    }
    
    public void setupUI(){
        setupLookAndFeel();
        setupGameAreaPanelUI();
        setupGameInfoPanelUI();
        setupHintsPanelUI();
    }

    /* setup Look and Fell using UIManager start *******************************************************************************/
    public void setupLookAndFeel(){  
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(WebSudokuApplet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(WebSudokuApplet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(WebSudokuApplet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedLookAndFeelException ex) {
            Logger.getLogger(WebSudokuApplet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    /* setup Look and Fell using UIManager end *******************************************************************************/

    /* setup game area panel UI component start *********************************************************************************************/
    public void setupGameAreaPanelUI(){

        /* initialize the UI components */
        determinePosLabel  = new JLabel[SIZE_DETERMINE_POS][NUM_CELLS_IN_UNIT] ;
        boxBorderLabel = new JLabel[BOX_LENGTH_IN_CELLS][BOX_LENGTH_IN_CELLS] ;
        cellsContainersPane = new JLayeredPane[NUM_CELLS_IN_UNIT][NUM_CELLS_IN_UNIT] ;
        cellsValueLabel = new JLabel[NUM_CELLS_IN_UNIT][NUM_CELLS_IN_UNIT] ;
        caluCellsLabel = new JLabel[NUM_CELLS_IN_UNIT][NUM_CELLS_IN_UNIT][NUM_CELLS_IN_UNIT] ;
        
        /* UI Component 0 -- setup determine position label -- JLabel */
        this.setupDeterminePosLabel();

        /* UI Component 1 -- setup the box border -- JLabel */
        this.setupBoxBorder();

        /* UI Component 2 -- setup the cell containers -- JLayeredPane */
        /* UI Component 3 -- setup the cell value labels -- JLabel */
        /* UI Component 4 -- setup the cell calculation labels -- JLabel */
        /* UI Component 5 -- setup the block pane, used when time stop -- JLayeredPane */
        this.setupCellComponents();

        /* UI Component 6 -- setup the control Label, that capture the mouse movement for operation -- JLabel */
        this.setupMouseControl();

        /* UI Component 7 -- setup the drag and drop input Label */
        this.setupDnDInputLabel();

        /* UI Component 8 -- default calcMode/ clickCalucells is true */
        isCalcMode = SudokuComponentsProperties.getIsFalse();
        isClickCaluCell = SudokuComponentsProperties.getIsFalse();
        isAutoHintsMode = SudokuComponentsProperties.getIsTrue();
    }
    public void setupDeterminePosLabel(){

        for( int i = 0 ; i < determinePosLabel.length ; ++i )
        {
            int determinePosStartX = 0 ;
            int determinePosStartY = 0 ;

            /* determinePosLabel i=0 horizontal i=1 vertical*/
            if( i==0 )
            {
                determinePosStartX = SIZE_CELL + GAME_START_POS;
                determinePosStartY = GAME_START_POS;
            }
            else
            {
                determinePosStartX = GAME_START_POS ;
                determinePosStartY = SIZE_CELL + GAME_START_POS ;
            }

            for( int j = 0 ; j < determinePosLabel[i].length ; ++j )
            {
                determinePosLabel[i][j] = new JLabel() ;
                determinePosLabel[i][j].setBackground(SudokuComponentsProperties.getColorBackground()) ;
                determinePosLabel[i][j].setFont(SudokuComponentsProperties.getFontDeterminePos()) ;
                determinePosLabel[i][j].setForeground(SudokuComponentsProperties.getColorPositionLabel()) ;
                determinePosLabel[i][j].setHorizontalAlignment(SudokuComponentsProperties.getAlgimentCenter()) ;

                if( 0 == i ) // the horizontal position
                {
                    determinePosLabel[i][j].setText( "" + ((char) (j + 1 + 64)) ) ;
                }
                else
                {
                    determinePosLabel[i][j].setText( "" + (j + 1) ) ;
                }
                determinePosLabel[i][j].setBounds( determinePosStartX, determinePosStartY, SIZE_CELL, SIZE_CELL ) ;
                GameAreaPanel.add(  determinePosLabel[i][j], javax.swing.JLayeredPane.DEFAULT_LAYER ) ;

                if(i==0 )
                {
                    determinePosStartX += SIZE_CELL ;
                }
                else
                {
                    determinePosStartY += SIZE_CELL ;
                }
            }
        }
    }
    public void setupBoxBorder(){

        for( int i = 0 ; i < boxBorderLabel.length ; ++i )
        {
            int boxPosX = ( i * SIZE_BOX) + CELL_START_POS;
            for( int j = 0 ; j < boxBorderLabel[i].length ; ++j )
            {
                int boxPosY = ( j * SIZE_BOX ) + CELL_START_POS ;
                //int boxIndex = boxBorderLabel[i].length * j + i + 1;
                //String[] Roman = SudokuComponentsProperties.getRoman();
                boxBorderLabel[i][j] = new JLabel() ;
                boxBorderLabel[i][j].setHorizontalAlignment(SudokuComponentsProperties.getAlgimentCenter());
                boxBorderLabel[i][j].setBackground(SudokuComponentsProperties.getColorBackground()) ;
                boxBorderLabel[i][j].setBorder(javax.swing.BorderFactory.createLineBorder(SudokuComponentsProperties.getColorBoxBorder()) ) ;
                boxBorderLabel[i][j].setForeground(SudokuComponentsProperties.getColorBoxForeground()) ;
                boxBorderLabel[i][j].setFont(SudokuComponentsProperties.getFontBox());
                boxBorderLabel[i][j].setBounds(boxPosX, boxPosY, SIZE_BOX, SIZE_BOX) ;
                GameAreaPanel.add(  boxBorderLabel[i][j], javax.swing.JLayeredPane.DEFAULT_LAYER ) ;
            }
        }
    }
    public void setupCellComponents(){

        for( int i = 0 ; i < cellsContainersPane.length ; ++i )
        {
            int cellPosX = ( i * SIZE_CELL ) + CELL_START_POS ;
            for( int j = 0 ; j < cellsContainersPane[0].length ; ++j )
            {
                int cellPosY = ( j * SIZE_CELL ) + CELL_START_POS ;

                /* UI Component 2: Cell containers */
                cellsContainersPane[i][j] = new JLayeredPane();
                cellsContainersPane[i][j].setOpaque(SudokuComponentsProperties.getIsTrue());
                cellsContainersPane[i][j].setBackground(SudokuComponentsProperties.getColorBackground()) ;
                cellsContainersPane[i][j].setBorder(BorderFactory.createLineBorder(SudokuComponentsProperties.getColorCellContainersBorder(), 1)) ;
                cellsContainersPane[i][j].setForeground(SudokuComponentsProperties.getColorCellContainersForeground()) ;
                cellsContainersPane[i][j].setBounds(cellPosX, cellPosY, SIZE_CELL, SIZE_CELL) ;
                GameAreaPanel.add(cellsContainersPane[i][j], javax.swing.JLayeredPane.DEFAULT_LAYER) ;

                /* UI Component 3: Cell Value */
                cellsValueLabel[i][j] = new JLabel() ;
                cellsValueLabel[i][j].setFont(SudokuComponentsProperties.getFontCellValue()) ;
                cellsValueLabel[i][j].setForeground(SudokuComponentsProperties.getColorCellValueForeground()) ;
                cellsValueLabel[i][j].setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
                cellsValueLabel[i][j].setText("") ;
                cellsValueLabel[i][j].setBounds(1, 1, SIZE_CELL, SIZE_CELL) ;
                cellsContainersPane[i][j].add(cellsValueLabel[i][j], SudokuComponentsProperties.getLayerIndexCellsValue()) ;
                cellsValueLabel[i][j].setVisible(SudokuComponentsProperties.getIsTrue()) ;

                
                /* UI Component 4: Cell Caluclation */
                int caluCellsPosX = 1 ;
                int caluCellsPosY = 1 ;

                for( int k = 0 ; k < caluCellsLabel[i][j].length ; ++k )
                {
                    final int VALUE_OF_CALU_CELL = k + 1 ;

                    if( (VALUE_OF_CALU_CELL % BOX_LENGTH_IN_CELLS) == 1 )
                    {
                        caluCellsPosX = 1 ;
                    }

                    caluCellsLabel[i][j][k] = new JLabel() ;
                    caluCellsLabel[i][j][k].setFont(SudokuComponentsProperties.getFontCaluCell());
                    caluCellsLabel[i][j][k].setForeground(SudokuComponentsProperties.getColorCalculationCellForeground());
                    caluCellsLabel[i][j][k].setHorizontalAlignment(SudokuComponentsProperties.getAlgimentCenter());
                    caluCellsLabel[i][j][k].setText(Integer.toString(VALUE_OF_CALU_CELL ));
                    caluCellsLabel[i][j][k].setBounds(caluCellsPosX, caluCellsPosY, SIZE_CALU_CELL, SIZE_CALU_CELL);
                    cellsContainersPane[i][j].add( caluCellsLabel[i][j][k], SudokuComponentsProperties.getLayerIndexCellsCalu()) ;
                    caluCellsLabel[i][j][k].setVisible(isCalcMode) ;

                    caluCellsPosX += SIZE_CALU_CELL ;
                    if( (VALUE_OF_CALU_CELL   % BOX_LENGTH_IN_CELLS) == 0 )
                    {
                        caluCellsPosY += SIZE_CALU_CELL ;
                    }
                }
            }
        }

        /* UI Component 5 -- setup the block pane, used when time stop -- JLayeredPane */
        BlockPane = new JLayeredPane();
        BlockPane.setBackground(SudokuComponentsProperties.getColorBlockPane());
        BlockPane.setOpaque(SudokuComponentsProperties.getIsTrue());
        BlockPane.setBounds(CELL_START_POS, CELL_START_POS,
                CELL_START_POS + (NUM_CELL_IN_UNIT-1) * SIZE_CELL, CELL_START_POS + (NUM_CELL_IN_UNIT-1) * SIZE_CELL);

        String pauseStr="";
        if(LangMode == ENG_MODE){
            pauseStr = "PAUSE";
        }
        if(LangMode == CHIN_MODE){
            pauseStr = "暫停";
        }
        JLabel BlockPaneText = new JLabel(pauseStr);
        BlockPaneText.setFont(SudokuComponentsProperties.getFontBlockPane());
        BlockPaneText.setHorizontalAlignment(SudokuComponentsProperties.getAlgimentCenter());
        BlockPaneText.setBounds(SudokuComponentsProperties.getBlockPanePos(), SudokuComponentsProperties.getBlockPanePos(),
                SudokuComponentsProperties.getBlockPaneSize(), SudokuComponentsProperties.getBlockPaneSize());
        GameAreaPanel.add(BlockPane, javax.swing.JLayeredPane.POPUP_LAYER);
        BlockPane.add(BlockPaneText);
        /* default as invisible */
        BlockPane.setVisible(SudokuComponentsProperties.getIsFalse());
    }
    /* For control the elimination calu cells*/
    /* This function only show the user sudoku */
     public void setupMouseControl(){

        /* the +1 refers to the determinePosLabel */
        final int SIZE_SUDOKU_GAME = (SIZE_CELL * (NUM_CELLS_IN_UNIT + 1)) ;

        controlLabel = new JLabel() ;
        controlLabel.setBounds( GAME_START_POS, GAME_START_POS, SIZE_SUDOKU_GAME, SIZE_SUDOKU_GAME ) ;
        GameAreaPanel.add(  controlLabel, javax.swing.JLayeredPane.DRAG_LAYER ) ;

        MouseListener controlMouseListener = new MouseListener() {

            public void mouseClicked(MouseEvent e) {
                final int clickPosX = (int)e.getX();
                final int clickPosY = (int)e.getY();
                final int clickCellCorX = clickPosX / SIZE_CELL -1;
                final int clickCellCorY = clickPosY / SIZE_CELL -1;
                final int clickCaluCellCorX = ( clickPosX % SIZE_CELL ) / SIZE_CALU_CELL;
                final int clickCaluCellCorY = ( clickPosY % SIZE_CELL ) / SIZE_CALU_CELL;
                final int caluCellPos = clickCaluCellCorY * BOX_LENGTH_IN_CELLS + clickCaluCellCorX;

                // to be improve ...
                /* record user steps */
                final boolean isVisibleCaluCellsLabel =  isCalcMode && caluCellsLabel[clickCellCorX][clickCellCorY][caluCellPos].isVisible();

                if(!Gameboard.isGivenCells(clickCellCorX, clickCellCorY) && isClickCaluCell
                        && cellsValueLabel[clickCellCorX][clickCellCorY].getText().equalsIgnoreCase("")){
                    /* Step 1 : record to stepList */
                    /* Step 2 : setupGameboard */
                    int cellIndex = IndexConverter.getIndex(clickCellCorX, clickCellCorY);
                    if(isVisibleCaluCellsLabel){
                        // 20091017 phrase2 start - comment
                        // Controller.recordSteps(cellIndex, caluCellPos+1, IMPOSSIBLE_CALU_VALUE_COMMAND);
                        // 20091017 phrase2 end
                        Gameboard.setImpossCellsValue(cellIndex, caluCellPos+1);
                    }
                    else{
                        // 20091017 phrase2 start - comment
                        //Controller.recordSteps(cellIndex, caluCellPos+1, POSSIBLE_CALU_VALUE_COMMAND);
                        // 20091017 phrase2 end
                        Gameboard.setPossCellsValue(cellIndex, caluCellPos+1);
                    }
                    
                    /* Step 3 : check redo/undo button */
                    // 20091017 phrase2 start - comment as calu cells are not used in redo undo , so don't need to check
                    //undoStepsButton.setEnabled(Controller.isUndoEnabled());
                    //redoStepsButton.setEnabled(Controller.isRedoEnabled());
                    // 20091017 phrase2 end
                    /* Step 4 : set the UI */
                    Controller.setVisibleCaluCellsLabel(clickCellCorX, clickCellCorY, caluCellPos, !isVisibleCaluCellsLabel);

                    /* TUTOR Step 1 : review learner steps - setTextLearnerStepsMsgBox */
                    if(isVisibleCaluCellsLabel){
                       
                       Controller.setTextEliminCaluCellValue(clickCellCorX, clickCellCorY, caluCellPos+1);
                       if(Controller.isElminHintsCell(Controller.getStrategyUnit(clickCellCorX, clickCellCorY))){
                            StrategyGraphUnit involvedUnit = new StrategyGraphUnit();
                            involvedUnit.copy(Controller.getElminHintsCell(Controller.getStrategyUnit(clickCellCorX, clickCellCorY)));
                            int[] involvedValue = Controller.getInvolvedValue(involvedUnit);

                            Controller.setCellElminBySystem(involvedUnit, involvedValue[0], 0);
                        }
                    }else{
                        Controller.setTextRecoverCaluCellValue(clickCellCorX, clickCellCorY, caluCellPos+1);
                    }

                }
            }
            public void mousePressed(MouseEvent e) {
            }
            public void mouseReleased(MouseEvent e) {
            }
            public void mouseEntered(MouseEvent e) {
            }
            public void mouseExited(MouseEvent e) {
            }
        };

        controlLabel.addMouseListener(controlMouseListener);
    }
    public void setupDnDInputLabel(){

        /* The additional one is for earse the value*/
        dndLabel = new JLabel[NUM_CELL_VALUE+1];
        int dndLabelPosX = SudokuComponentsProperties.getDnDInputPosX();
        int dndLabelPosY = SudokuComponentsProperties.getDnDInputPosY();

        for(int i=0; i<dndLabel.length; i++){
            dndLabel[i] = new JLabel();
            dndLabel[i].setFont(SudokuComponentsProperties.getFontDnDLabel());
            dndLabel[i].setForeground(SudokuComponentsProperties.getColorDnDLabelForeground());
            dndLabel[i].setHorizontalAlignment(SudokuComponentsProperties.getAlgimentCenter());
            dndLabel[i].setBorder(javax.swing.BorderFactory.createLineBorder(SudokuComponentsProperties.getColorDnDLabelBorder(), 1)) ;
            if(i==0){
                String eraseStr = "";
                if(LangMode == ENG_MODE){
                    eraseStr = "Erase";
                }
                if(LangMode == CHIN_MODE){
                    eraseStr = "擦掉";
                }
                dndLabel[i].setText(eraseStr);
                dndLabel[i].setBounds(dndLabelPosX, dndLabelPosY, SIZE_CELL*3/2, SIZE_CELL);
                dndLabelPosX += SIZE_CELL*3/2;
            }else{
                dndLabel[i].setText(Integer.toString(i));
                dndLabel[i].setBounds(dndLabelPosX, dndLabelPosY, SIZE_CELL, SIZE_CELL);
                dndLabelPosX += SIZE_CELL;
            }
            GameAreaPanel.add( dndLabel[i]) ;
        }
    }
    /* setup game area panel UI component end***************************************************************************************************/

    /* setup GameInfoPanel UI component start ***********************************************************************************************/
    public void setupGameInfoPanelUI(){

        /* UI component 1 : Setup related STATIC labels*/
        /* Label text :
         * Difficulties, Rules Priority, 1, 2, 3, 4, 5, 6
         * Supporting Start Button Label
         */
        setupGameInfoLabel();
        /* UI component 2 : Difficulty of Game using JSpinner */
        setupDifficultySpinner();
        /* UI component 3 : Rules setting priority using JSpinner */
        setupLogicalRulesSpinner();
        /* UI component 4 : Start Game Button */
        setupStartGameButton();
        /* UI component 5 : Setup timer */
        setupTimer();
        /* UI component 6 : Setup solving status */
        setupSolvingStatus();
        /* UI component 7 : Setup Hints status */
        setupHintsStatus();
        /* UI component 8 : Setup redo/undo Button */
        setupStepsManagementButton();
        /* UI component 9 : add check boxes  - enable calu cell visible & auto hints giving */
        setupCheckBoxes();
    }
    public void setupGameInfoLabel(){

        JLabel DifficultyLabel = new JLabel();
        JLabel RulesPriorityLabel = new JLabel();
        JLabel[] PriorityNumLabel = new JLabel[SudokuGameInfoParam.getLogicalRules().length];
        JLabel SupportStartLabel = new JLabel();
        JLabel TimerLabel = new JLabel();
        JLabel SolvingStatusLabel = new JLabel();
        JLabel HintsStatusLabel = new JLabel();
        JLabel SettingsLabel = new JLabel();
        JLabel[] HintsLabel = new JLabel[SudokuGameInfoParam.getHintsLevel().length];
        if(LangMode == ENG_MODE){
            DifficultyLabel.setText("Difficulty : ");
            RulesPriorityLabel.setText("Rules Priority : ");
            SupportStartLabel.setText("Game with below settings ");
            TimerLabel.setText("Time Elapsed : ");
            SolvingStatusLabel.setText("Remainning cell(s) : ");
            HintsStatusLabel.setText("Number of Hint(s) : ");
            SettingsLabel.setText("Settings : ");
        }
        if(LangMode == CHIN_MODE){
            DifficultyLabel.setText("困難程度 : ");
            RulesPriorityLabel.setText("規則優先 : ");
            SupportStartLabel.setText("遊戲設置");
            TimerLabel.setText("所用時間 : ");
            SolvingStatusLabel.setText("未有答案發 : ");
            HintsStatusLabel.setText("所用提示 : ");
            SettingsLabel.setText("設置 : ");
        }

        /* setup supporting start button label */
        SupportStartLabel.setBounds(START_LABEL_POSX, START_LABEL_POSY , WSIZE_STATIC_LABEL, LSIZE);
        SupportStartLabel.setFont(SudokuComponentsProperties.getFontSupportStartLabel());
        GameInfoPanel.add(SupportStartLabel);

        /* setup difficulty label */
        DifficultyLabel.setBounds(DIFFICULTY_POSX, DIFFICULTY_POSY, WSIZE_STATIC_LABEL, LSIZE);
        DifficultyLabel.setFont(SudokuComponentsProperties.getFontItemsLabel());
        GameInfoPanel.add(DifficultyLabel);

        /*  setup rules priority label */
        /* *2 : 1 for the label and 1 for the spinner (diffculty label) */
        RulesPriorityLabel.setBounds(PRIORITY_POSX, PRIORITY_POSY, WSIZE_STATIC_LABEL, LSIZE);
        RulesPriorityLabel.setFont(SudokuComponentsProperties.getFontItemsLabel());
        GameInfoPanel.add(RulesPriorityLabel);
        
        for (int i=0; i < SudokuGameInfoParam.getLogicalRules().length; i++){

            /* LSIZE of Label + Spinner */
            int REVISED_START_POSY = PRIORITY_POSY + LSIZE + (SPINNER_SPACING + LSIZE)*i;
            PriorityNumLabel[i] = new JLabel();
            PriorityNumLabel[i].setBounds(PRIORITY_POSX, REVISED_START_POSY, WSIZE_BULLET, LSIZE);
            PriorityNumLabel[i].setText(Integer.toString(i+1) + ". ");
            PriorityNumLabel[i].setFont(SudokuComponentsProperties.getFontItemsLabel());
            GameInfoPanel.add(PriorityNumLabel[i]);

        }

        /* setup timer Label */
        TimerLabel.setBounds(TIMER_LABEL_POS_X, TIMER_LABEL_POS_Y, WSIZE_STATIC_LABEL, LSIZE);
        TimerLabel.setFont(SudokuComponentsProperties.getFontItemsLabel());
        GameInfoPanel.add(TimerLabel);

        /* setup solving status - give the remainning cells to be solved */
       SolvingStatusLabel.setBounds(SOLVING_STATUS_LABEL_POSX, SOLVING_STATUS_LABEL_POSY, WSIZE_STATIC_LABEL, LSIZE);
       SolvingStatusLabel.setFont(SudokuComponentsProperties.getFontItemsLabel());
       GameInfoPanel.add(SolvingStatusLabel);

       /* setup hints status - give the hints used  to be solved */
       HintsStatusLabel.setBounds(HINTS_STATUS_LABEL_POSX, HINTS_STATUS_LABEL_POSY, WSIZE_STATIC_LABEL, LSIZE);
       HintsStatusLabel.setFont(SudokuComponentsProperties.getFontItemsLabel());
       GameInfoPanel.add(HintsStatusLabel);

       String[] HintsLevel = SudokuGameInfoParam.getHintsLevel();
       String[] HintsLevelInChin = SudokuGameInfoParam.getHintsLevelInChin();
       for(int i=0; i < SudokuGameInfoParam.getHintsLevel().length; i++){
            HintsLabel[i] = new JLabel();
            int REVISED_START_POSY = HINTS_STATUS_LABEL_POSY + LSIZE + (LSIZE_VARIABLE + SPINNER_SPACING)*i;
            HintsLabel[i].setBounds(HINTS_STATUS_LABEL_POSX, REVISED_START_POSY, WSIZE_BULLET+WSIZE_HINTS_LABEL, LSIZE_VARIABLE);
            if(LangMode == ENG_MODE){
                HintsLabel[i].setText(Integer.toString(i+1) + ". " +  HintsLevel[i]);
            }
            if(LangMode == CHIN_MODE){
                HintsLabel[i].setText(Integer.toString(i+1) + ". " +  HintsLevelInChin[i]);
            }
            HintsLabel[i].setFont(SudokuComponentsProperties.getFontItemsLabel());
            GameInfoPanel.add(HintsLabel[i]);
       }

       /* setup game status - give immediate response to user */
       GameStatus = new JLabel();
       if(LangMode == ENG_MODE){
           GameStatus.setText(GAME_STATUS_CORRECT);
       }
       if(LangMode == CHIN_MODE){
           GameStatus.setText(GAME_STATUS_CORRECT_IN_CHIN);
       }
       GameStatus.setBounds(GAME_STATUS_LABEL_POSX, GAME_STATUS_LABEL_POSY, WSIZE_STATIC_LABEL, LSIZE);
       GameStatus.setFont(SudokuComponentsProperties.getFontGameStatus());
       GameInfoPanel.add(GameStatus);

       /* add seperator for redo and undo button */
       settingSeparator = new JSeparator(SwingConstants.HORIZONTAL);
       settingSeparator.setBounds(SEPARATOR_POSX, SEPARATOR_POSY, WSIZE_SEPARATOR, LSIZE_SEPARATOR);
       GameInfoPanel.add(settingSeparator);
       /* add setting labels */
       SettingsLabel.setBounds(SEPARATOR_POSX, SEPARATOR_POSY + LSIZE_SEPARATOR, WSIZE_STATIC_LABEL, LSIZE);
       SettingsLabel.setFont(SudokuComponentsProperties.getFontItemsLabel());
       GameInfoPanel.add(SettingsLabel);

    }
    public void setupDifficultySpinner(){

        final String[] DIFFICULTY_LEVELS = SudokuGameInfoParam.getDifficultyLevels();
        final String[] DIFFICULTY_LEVELS_IN_CHIN = SudokuGameInfoParam.getDifficultyLevelsInChin();

        difficultSpinnerHandler =
                new SpinnerHandler(difficultSpinner, GameInfoPanel);
        if(LangMode == ENG_MODE){
            difficultSpinnerHandler.setupSpinner(DIFFICULTY_POSX + WSIZE_BULLET, DIFFICULTY_POSY + LSIZE, DIFFICULTY_LEVELS, 0);
        }
        if(LangMode == CHIN_MODE){
            difficultSpinnerHandler.setupSpinner(DIFFICULTY_POSX + WSIZE_BULLET, DIFFICULTY_POSY + LSIZE, DIFFICULTY_LEVELS_IN_CHIN, 0);
        }
    }
    public void setupLogicalRulesSpinner(){

        logicalRulesPriority = new JSpinner[LOGICAL_RULES.length];
        logicalRulesPrioritySpinnerHandler = new SpinnerHandler[LOGICAL_RULES.length];
        for (int i=0; i < logicalRulesPriority.length; i++){
            int REVISED_START_POSX = PRIORITY_POSX + WSIZE_BULLET;
            int REVISED_START_POSY = PRIORITY_POSY + LSIZE + (SPINNER_SPACING + LSIZE)*i;
            logicalRulesPrioritySpinnerHandler[i] = new SpinnerHandler(logicalRulesPriority[i], GameInfoPanel);
            if(LangMode == ENG_MODE){
                logicalRulesPrioritySpinnerHandler[i].setupSpinner(REVISED_START_POSX, REVISED_START_POSY, LOGICAL_RULES, i);
            }
            if(LangMode == CHIN_MODE){
                logicalRulesPrioritySpinnerHandler[i].setupSpinner(REVISED_START_POSX, REVISED_START_POSY, LOGICAL_RULES_IN_CHIN, i);
            }

        }
    }
    public void setupStartGameButton(){
        String startStr="";
        if(LangMode == ENG_MODE){
            startStr = "START";
        }
        if(LangMode == CHIN_MODE){
            startStr = "開始";
        }

        startGameButton = new JButton(startStr);
        startGameButton.setBounds(START_BUTTON_POSX, START_BUTTON_POSY, WSIZE_BUTTON, LSIZE_BUTTON);
        startGameButton.setBackground(SudokuComponentsProperties.getColorButtonBackground());
        startGameButton.setForeground(SudokuComponentsProperties.getColorButtonForeground());
        startGameButton.setFont(SudokuComponentsProperties.getFontButton());
        GameInfoPanel.add(startGameButton);

        /* Perform action when button pressed*/
        startGameButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                StartButtonActionPerform();
            }
        });
    }
    public void setupTimer(){
        /* setup timer */
        Timer = new TimerHandler();
        Timer.setBounds(TIMER_LABEL_POS_X, TIMER_LABEL_POS_Y + LSIZE , WSIZE_VARIABLE, LSIZE_VARIABLE);
        Timer.setFont(SudokuComponentsProperties.getFontSpecial());
        GameInfoPanel.add(Timer);
        Timer.ReSet();

        /* setup timer control button */
        String stopStr="";
        if(LangMode == ENG_MODE){
           stopStr = "STOP";
        }
        if(LangMode == CHIN_MODE){
            stopStr = "停止";
        }
        TimerControlButton = new JButton(stopStr);
        TimerControlButton.setBounds(TIMER_LABEL_POS_X + WSIZE_VARIABLE, TIMER_LABEL_POS_Y + LSIZE, WSIZE_BUTTON, LSIZE_BUTTON);
        TimerControlButton.setBackground(SudokuComponentsProperties.getColorButtonBackground());
        TimerControlButton.setForeground(SudokuComponentsProperties.getColorButtonForeground());
        TimerControlButton.setFont(SudokuComponentsProperties.getFontButton());
        /* default button as disable */
        TimerControlButton.setEnabled(SudokuComponentsProperties.getIsFalse());
        //GameInfoPanel.add(TimerControlButton);

        TimerControlButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               TimerControlButtonActionPerform();
            }
        });
    }
    public void setupSolvingStatus(){
        /* Cannot use controler ass controller haven't set up here */
        SolvingStatus = new JLabel("0");
        SolvingStatus.setForeground(SudokuComponentsProperties.getColorSpecial());
        SolvingStatus.setBounds(SOLVING_STATUS_LABEL_POSX, SOLVING_STATUS_LABEL_POSY + LSIZE ,  WSIZE_VARIABLE, LSIZE_VARIABLE);
        SolvingStatus.setFont(SudokuComponentsProperties.getFontSpecial());
        GameInfoPanel.add(SolvingStatus);
    }
    public void setupHintsStatus(){
        /* Cannot use controler ass controller haven't set up here */
        HintsStatus = new JLabel[HINTS_LEVEL.length];
        NumHintsGivenOn = new int[HINTS_LEVEL.length];
        for(int i=0; i<HINTS_LEVEL.length; i++){
            NumHintsGivenOn[i] = 0;
            HintsStatus[i] = new JLabel(Integer.toString(NumHintsGivenOn[i]));
            int REVISED_START_POSX = HINTS_STATUS_LABEL_POSX + WSIZE_BULLET + WSIZE_HINTS_LABEL;
            int REVISED_START_POSY = HINTS_STATUS_LABEL_POSY + LSIZE + (LSIZE_VARIABLE + SPINNER_SPACING)*i;
            HintsStatus[i].setForeground(SudokuComponentsProperties.getColorSpecial());
            HintsStatus[i].setBounds(REVISED_START_POSX, REVISED_START_POSY,  WSIZE_HINTS_VARIABLE, LSIZE_VARIABLE);
            HintsStatus[i].setFont(SudokuComponentsProperties.getFontSpecial());
            HintsStatus[i].setHorizontalAlignment(SudokuComponentsProperties.getAlgimentRight());
            GameInfoPanel.add(HintsStatus[i]);
        }

        /* Hints request Label */
        HintsRequestButton = new JButton[HINTS_LEVEL.length];
        for(int i =0; i<HINTS_LEVEL.length; i++){
            String hintsStr="";
            if(LangMode == ENG_MODE){
               hintsStr = "HINTS";
            }
            if(LangMode == CHIN_MODE){
                hintsStr = "提示";
            }
            HintsRequestButton[i] = new JButton(hintsStr);
            int REVISED_START_POSX = HINTS_STATUS_LABEL_POSX + WSIZE_BULLET + WSIZE_HINTS_VARIABLE + WSIZE_HINTS_LABEL;
            int REVISED_START_POSY = HINTS_STATUS_LABEL_POSY + LSIZE + (LSIZE_VARIABLE + SPINNER_SPACING)*i;
            HintsRequestButton[i].setBounds(REVISED_START_POSX, REVISED_START_POSY, WSIZE_BUTTON, LSIZE_BUTTON);
            HintsRequestButton[i].setBackground(SudokuComponentsProperties.getColorButtonBackground());
            HintsRequestButton[i].setForeground(SudokuComponentsProperties.getColorButtonForeground());
            HintsRequestButton[i].setFont(SudokuComponentsProperties.getFontButton());
            /* default button as disable */
            HintsRequestButton[i].setEnabled(SudokuComponentsProperties.getIsFalse());
            final int hintsLevel = i;
            HintsRequestButton[i].addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                   HintsButtonActionPerform(hintsLevel);
                }
            });
            GameInfoPanel.add(HintsRequestButton[i]);
        }
    }

    public void setupStepsManagementButton(){
        
        String undoStr="";
        String redoStr="";
        if(LangMode == ENG_MODE){
           undoStr = "UNDO";
           redoStr = "REDO";
        }
        if(LangMode == CHIN_MODE){
            undoStr = "還原";
            redoStr  ="重做";
        }
        /* setup undo button */
        undoStepsButton = new JButton(undoStr);
        undoStepsButton.setBounds(STEPS_MANAGE_BUTTON_POSX, STEPS_MANAGE_BUTTON_POSY, WSIZE_BUTTON, LSIZE_BUTTON);
        undoStepsButton.setBackground(SudokuComponentsProperties.getColorButtonBackground());
        undoStepsButton.setForeground(SudokuComponentsProperties.getColorButtonForeground());
        undoStepsButton.setFont(SudokuComponentsProperties.getFontButton());
        undoStepsButton.setEnabled(SudokuComponentsProperties.getIsFalse());
        //GameInfoPanel.add(undoStepsButton);
        /* setup redo button */
        redoStepsButton = new JButton(redoStr);
        redoStepsButton.setBounds(STEPS_MANAGE_BUTTON_POSX + ITEM_SEPERATOR_SPACING + WSIZE_BUTTON , STEPS_MANAGE_BUTTON_POSY, WSIZE_BUTTON, LSIZE_BUTTON);
        redoStepsButton.setBackground(SudokuComponentsProperties.getColorButtonBackground());
        redoStepsButton.setForeground(SudokuComponentsProperties.getColorButtonForeground());
        redoStepsButton.setFont(SudokuComponentsProperties.getFontButton());
        redoStepsButton.setEnabled(SudokuComponentsProperties.getIsFalse());
        //GameInfoPanel.add(redoStepsButton);

        /* Perform action when button pressed*/
        undoStepsButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               UndoButtonActionPerform();
            }
        });

        redoStepsButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                RedoButtonActionPerform();
            }
        });
    }
    public void setupCheckBoxes(){
        String showCellStr="";
        String autoHintStr="";
        if(LangMode == ENG_MODE){
           showCellStr = "Show calculation cells";
           autoHintStr = "Enable Auto Hints Giving";
        }
        if(LangMode == CHIN_MODE){
            showCellStr = "顯示計算細胞 ";
            autoHintStr  ="啟用自動給予提示";
        }

        /* Visible calu cells */
        caluCellsCheckBox = new JCheckBox(showCellStr);
        caluCellsCheckBox.setMnemonic(KeyEvent.VK_C);
        caluCellsCheckBox.setSelected(SudokuComponentsProperties.getIsTrue());
        caluCellsCheckBox.setBackground(SudokuComponentsProperties.getColorBackground());
        caluCellsCheckBox.setBounds(CALU_CELLS_CLICK_POSX, CALU_CELLS_CLICK_POSY ,WSIZE_STATIC_LABEL, LSIZE);
        GameInfoPanel.add(caluCellsCheckBox);
        caluCellsCheckBox.setEnabled(SudokuComponentsProperties.getIsFalse());
        /* Enable auto hints giving */
        autoHintsCheckBox = new JCheckBox(autoHintStr);
        autoHintsCheckBox.setMnemonic(KeyEvent.VK_C);
        autoHintsCheckBox.setSelected(SudokuComponentsProperties.getIsTrue());
        autoHintsCheckBox.setBackground(SudokuComponentsProperties.getColorBackground());
        autoHintsCheckBox.setBounds(AUTO_HINTS_CLICK_POSX, AUTO_HINTS_CLICK_POSY , WSIZE_STATIC_LABEL, LSIZE);
        GameInfoPanel.add(autoHintsCheckBox);
        autoHintsCheckBox.setEnabled(SudokuComponentsProperties.getIsFalse());

        caluCellsCheckBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               ShowCaluCellsCheckBoxActionPerform();
            }
        });
        autoHintsCheckBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               EnableAutoHintsCheckBoxActionPerform();
            }
        });

    }
    /* undo & redo button action perform start**********************************************************************/
    public void UndoButtonActionPerform(){
        String undoSteps = Controller.undoSteps();
        final int index = Controller.getCellPosition(undoSteps);
        final int indexX = IndexConverter.getHorizontalIndex(index);
        final int indexY = IndexConverter.getVerticalIndex(index);
        final int involvedValue = Controller.getInvolvedValue(undoSteps);
        final String actionCommand = Controller.getActionCommand(undoSteps);

        /* Step 1 : update UI */
        if(actionCommand.equalsIgnoreCase(ERASE_VALUE_COMMAND)){
            Gameboard.setCellValue(indexX, indexY, involvedValue);
            /* set for tutor*/
            Controller.isLearnerInputCorrect(indexX, indexY, involvedValue);
            Controller.setTextAssignCellValue(indexX, indexY, involvedValue);
            /* Update Expert */
            Controller.setCellDefiniteValue(indexX, indexY, involvedValue);
        }
        else if (actionCommand.equalsIgnoreCase(ASSIGN_VALUE_COMMAND)){
            Gameboard.setCellValue(indexX, indexY, 0);
            /* set for tutor*/
            Controller.isLearnerInputCorrect(indexX, indexY, 0);
            Controller.setTextEraseCellValue(indexX, indexY, involvedValue);
            /* update expert */
            if(Controller.getDefiniteValueSet(indexX, indexY)){
                /* refresh the poss value */
                Controller.removeDefiniteValue(indexX, indexY);
            }
        }
        // 20091017 phrase2 start - comment
        /*else if (actionCommand.equalsIgnoreCase(POSSIBLE_CALU_VALUE_COMMAND)){
            Gameboard.setImpossCellsValue(index, involvedValue);
            Controller.setTextEliminCaluCellValue(indexX, indexY, involvedValue);
        }
        else if (actionCommand.equalsIgnoreCase(IMPOSSIBLE_CALU_VALUE_COMMAND)){
            Gameboard.setPossCellsValue(index, involvedValue);
            Controller.setTextRecoverCaluCellValue(indexX, indexY, involvedValue);
        }*/
        // 20091017 phrase2 end
        this.refreshGameboard();
        /* Step 2 : check Redo Button Enabled */
        redoStepsButton.setEnabled(Controller.isRedoEnabled());
        /* Step 3 : check undo Button Enabled */
        undoStepsButton.setEnabled(Controller.isUndoEnabled());

        
        /* TUTOR STEP 1 : check for the correctness of after redo button presses */
        boolean isCorrectGameboard = Controller.isLearnerInputAllCorrect();
        if(isCorrectGameboard){
            Controller.setTextGameStatus(GAME_STATUS_CORRECT);
        }
        else{
            Controller.setTextGameStatus(GAME_STATUS_WRONG);
        }
        /* TUTOR STEP 2 : update number of cells solved */
        Controller.setTextSolvingStatus(Controller.getNumCellsUnsolved());
        /* EXPERT STEP 1: update the logical rules applied */
        // 20091019 phrase2 start
        Controller.setupStepsMatrix(Controller.applyLogicalRules());
        // 20091019 phrase2 end
    }
    public void RedoButtonActionPerform(){
        String redoSteps = Controller.redoSteps();
        final int index = Controller.getCellPosition(redoSteps);
        final int indexX = IndexConverter.getHorizontalIndex(index);
        final int indexY = IndexConverter.getVerticalIndex(index);
        final int involvedValue = Controller.getInvolvedValue(redoSteps);
        final String actionCommand = Controller.getActionCommand(redoSteps);
        /* Step 1 : update UI */
        if(actionCommand.equalsIgnoreCase(ERASE_VALUE_COMMAND)){
            Gameboard.setCellValue(indexX, indexY, 0);
            /* set for tutor*/
            Controller.isLearnerInputCorrect(indexX, indexY, 0);
            Controller.setTextEraseCellValue(indexX, indexY, involvedValue);
            /* update expert */
            if(Controller.getDefiniteValueSet(indexX, indexY)){
                /* refresh the poss value */
                Controller.removeDefiniteValue(indexX, indexY);
            }
        }
        else if (actionCommand.equalsIgnoreCase(ASSIGN_VALUE_COMMAND)){
            Gameboard.setCellValue(indexX, indexY, involvedValue);
            /* set for tutor*/
            Controller.isLearnerInputCorrect(indexX, indexY, involvedValue);
            Controller.setTextAssignCellValue(indexX, indexY, involvedValue);
            /* Update Expert */
            Controller.setCellDefiniteValue(indexX, indexY, involvedValue);
        }
        else if (actionCommand.equalsIgnoreCase(POSSIBLE_CALU_VALUE_COMMAND)){
            Gameboard.setPossCellsValue(index, involvedValue);
            Controller.setTextRecoverCaluCellValue(indexX, indexY, involvedValue);
        }
        else if (actionCommand.equalsIgnoreCase(IMPOSSIBLE_CALU_VALUE_COMMAND)){
            Gameboard.setImpossCellsValue(index, involvedValue);
            Controller.setTextEliminCaluCellValue(indexX, indexY, involvedValue);
        }
        this.refreshGameboard();
        /* Step 2 : check Redo Button Enabled */
        redoStepsButton.setEnabled(Controller.isRedoEnabled());
        /* Step 3 : check undo Button Enabled */
        undoStepsButton.setEnabled(Controller.isUndoEnabled());

        /* TUTOR STEP 1 : check for the correctness of after redo button presses */
        boolean isCorrectGameboard = Controller.isLearnerInputAllCorrect();
        if(isCorrectGameboard){
            Controller.setTextGameStatus(GAME_STATUS_CORRECT);
        }
        else{
            Controller.setTextGameStatus(GAME_STATUS_WRONG);
        }
        /* TUTOR STEP 2 : update number of cells solved */
        Controller.setTextSolvingStatus(Controller.getNumCellsUnsolved());
        /* EXPERT STEP 1: update the logical rules applied */
        // 20091019 phrase2 start
        Controller.setupStepsMatrix(Controller.applyLogicalRules());
        // 20091019 phrase2 end
    }
    /* undo & redo button action perform end**********************************************************************/
    /* Hints Button action perform start**************************************************************/
    public void HintsButtonActionPerform(int inputHintsLevel){
        int numOfHints = Controller.getNumHintsUsed(inputHintsLevel) + 1;
        HintsStatus[inputHintsLevel].setText(Integer.toString(numOfHints));
        Controller.setTextLearnerStepsMsgBox(Controller.getHints(inputHintsLevel));
        // 20091112 phrase2 start
        Controller.reStartAutoHintsTimer(inputHintsLevel);
        // 20091112 phrase2 end
    }
    /* Hints Button action perform end****************************************************************/
    /* show Calu cells CheckBox action perform start**************************************************************/
    public void ShowCaluCellsCheckBoxActionPerform(){
        // 20091016 phrase2 start
        JOptionPane.showConfirmDialog(null, "EnableCaluCellsCheckBox Click !!!", OptionTitle, JOptionPane.YES_OPTION);
        //isCalcMode = caluCellsCheckBox.isSelected();
        // 20091016 phrase2 end
        this.refreshGameboard();
    }
    /*show Calu cells CheckBox action perform end****************************************************************/
    /* Enable auto hints CheckBox action perform start**************************************************************/
    public void EnableAutoHintsCheckBoxActionPerform(){
        // 20091112 phrase2 start
        isAutoHintsMode = !isAutoHintsMode;
        Controller.reStartAutoHintsTimer(-1);
        Controller.isEnableAutoHints(isAutoHintsMode);

        // 20091112 phrese2 end
    }
    /* Enable auto hints CheckBox action perform end****************************************************************/
    /* TimerControlButton action perform start**************************************************************/
    public void TimerControlButtonActionPerform(){
        /* Step 1 : set the timer */
        /* Step 2 : set the button text */
        /* Step 3 : set the Block Pane */
        /* Step 4 : set the DnD handler */
        /* Step 5 : set the redo & undo Button */
        /* Step 6 : set click calu cells */
        /* Step 7 : set hints request button */
        /* Step 8 : set the setting check box */

        boolean isButtonOrgEnable = Timer.isEnabled();

        String stopStr="";
        String resumeStr="";
        if(LangMode == ENG_MODE){
           stopStr = "STOP";
           resumeStr = "RESUME";
        }
        if(LangMode == CHIN_MODE){
            stopStr = "停止";
            resumeStr  ="繼續";
        }

        if(isButtonOrgEnable){
            Timer.setEnabled(SudokuComponentsProperties.getIsFalse());
            Timer.StopTimer();
            TimerControlButton.setText(resumeStr);
            BlockPane.setVisible(SudokuComponentsProperties.getIsTrue());
            DnD.isDNDFunctionEnable(SudokuComponentsProperties.getIsFalse());
            undoStepsButton.setEnabled(SudokuComponentsProperties.getIsFalse());
            redoStepsButton.setEnabled(SudokuComponentsProperties.getIsFalse());
            isClickCaluCell = SudokuComponentsProperties.getIsFalse();
            for(int i = 0; i<HintsRequestButton.length; i++){
                HintsRequestButton[i].setEnabled(SudokuComponentsProperties.getIsFalse());
            }
            caluCellsCheckBox.setEnabled(SudokuComponentsProperties.getIsFalse());
            autoHintsCheckBox.setEnabled(SudokuComponentsProperties.getIsFalse());
        }else{
            Timer.setEnabled(SudokuComponentsProperties.getIsTrue());
            Timer.StartTimer();
            TimerControlButton.setText(stopStr);
            BlockPane.setVisible(SudokuComponentsProperties.getIsFalse());
            DnD.isDNDFunctionEnable(SudokuComponentsProperties.getIsTrue());
            undoStepsButton.setEnabled(Controller.isUndoEnabled());
            redoStepsButton.setEnabled(Controller.isRedoEnabled());
            isClickCaluCell = SudokuComponentsProperties.getIsTrue();
            for(int i = 0; i<HintsRequestButton.length; i++){
                HintsRequestButton[i].setEnabled(SudokuComponentsProperties.getIsTrue());
            }
            caluCellsCheckBox.setEnabled(SudokuComponentsProperties.getIsTrue());
            autoHintsCheckBox.setEnabled(SudokuComponentsProperties.getIsTrue());
        }
    }
    /* TimerControlButton action perform end****************************************************************/
    /* start button action perform start**********************************************************************/
    public void StartButtonActionPerform(){
        /* Interface */
        /* 1. check duplication of the rules priority set */
        /* 2. check the game user haven't play yet */
        /* 3. check the difficulty */
        /* 4. gameboard setting */
        /* 5. activate the timer, hints */
        /* 6. activate check box */
        /* 7. activate DnD functions */
        /* 8. record learner steps */
        /* 9. set solving status */
        /* ExpertModel */
        /* 1. get corresponding learner's request difficulty game and set game difficulty */
        /* 2. update expert cell possibility graph */
        /* TutorModel */
        /* 1. setup TutorModel with solved answer */
        /* 2. setup the rules found on at the moment */
        /* 3. setRulesRanking */
        /* 4. setup auto hints giving timer */

        /* UI onButtonPressed Step 1. set RulesRanking*/
        Controller.setUserID(UserID);
        boolean isSettingsCorrect = this.checkInputSetting();

        if(isSettingsCorrect){
            /* EXPERT onButtonPressed Step 1 : get corresponding learner's request difficulty game*/

            Hashtable resultTable=this.getGamePuzzles();
            boolean isGameAvailable = (resultTable.size()!=0);

            if(isGameAvailable){
                /* UI onButtonPressed Step 2 : invisible start button, visible stopButton*/
                this.setButtonDisableAfterStart();
                /* UI onButtonPressed Step 3 : extract Database data */
                final String[] TABLE_GAME_PUZZLES_PARAM = DatabaseParam.getTableGamePuzzlesParam();
                /* Parameters of the result set */
                final int PuzzleID = (Integer)resultTable.get("PuzzleID");
                int[][] DefiniteNum = new int[NUM_CELL_VALUE][];
                for(int i=0; i<DefiniteNum.length; i++){
                    int number = i+1;
                    DefiniteNum[i] = (int[])resultTable.get("DefiniteValue"+ number);
                }
                final int[] GivenCells = (int[])resultTable.get("GivenCells");
                
                /* UI onButtonPressed Step 4 : gameboard setting */
                setGameboard(GivenCells,  DefiniteNum);

                /* UI onButtonPressed Step 5 : StartTimer */
                Timer.StartTimer();
                /* enable timer button */
                TimerControlButton.setEnabled(SudokuComponentsProperties.getIsTrue());
                for(int i = 0; i<HintsRequestButton.length; i++){
                   HintsRequestButton[i].setEnabled(SudokuComponentsProperties.getIsTrue());
                }

                /* UI onButtonPressed Step 6 : Allow Settings */
                caluCellsCheckBox.setEnabled(SudokuComponentsProperties.getIsTrue());
                autoHintsCheckBox.setEnabled(SudokuComponentsProperties.getIsTrue());
                /* UI onButtonPressed Step 7 : Enable DnD functions to perform */
                DnD.isDNDFunctionEnable(SudokuComponentsProperties.getIsTrue());
                isClickCaluCell = SudokuComponentsProperties.getIsTrue();

                /* EXPERT onButtonPressed Step 2 : Set Given Cells Information */
                /* Set number given cell */
                Controller.setNumGivenCells(GivenCells.length);
                /* Set cell possibility graph */
                for(int i=0; i<GivenCells.length; i++){
                    final int indexX = IndexConverter.getHorizontalIndex(GivenCells[i]);
                    final int indexY = IndexConverter.getVerticalIndex(GivenCells[i]);
                    Controller.setGivenCellDefiniteValue(indexX, indexY, Gameboard.getDefiniteCellValue(indexX, indexY));
                }

                /* UI onButtonPressed Step 8 : record learner steps - 1. difficulity, 2. logical rules priority */
                StringBuffer displayStr = new StringBuffer();
                if(LangMode == ENG_MODE){
                    displayStr.append("Game Started with\n");
                    displayStr.append("UserID : \n");
                    displayStr.append("\t"+UserID+"\n");
                    displayStr.append("Puzzle ID : \n");
                    displayStr.append("\t"+PuzzleID+"\n");
                    Controller.setPuzzleID(Integer.toString(PuzzleID));
                    displayStr.append("Difficulty : \n");
                    displayStr.append("\t"+difficultSpinnerHandler.getSpinnerValue()+"\n");
                    Controller.setDifficulty(difficultSpinnerHandler.getSpinnerValue());
              
                    displayStr.append("Rules priority :\n");
                    for (int i=0; i<logicalRulesPrioritySpinnerHandler.length; i++){
                        displayStr.append("\t" + Integer.toString(i+1) +".");
                        displayStr.append(logicalRulesPrioritySpinnerHandler[i].getSpinnerValue()+"\n");
                        Controller.setRulesPriority(logicalRulesPrioritySpinnerHandler[i].getSpinnerValue(), i);

                    }
                    displayStr.append(HINTS_PANEL_SEPARATOR);
                }
                if(LangMode == CHIN_MODE){
                    displayStr.append("遊戲開始\n");
                    displayStr.append("使用者辯證碼 : \n");
                    displayStr.append("\t"+UserID+"\n");
                    displayStr.append("數獨編號 : \n");
                    displayStr.append("\t"+PuzzleID+"\n");
                    Controller.setPuzzleID(Integer.toString(PuzzleID));
                    displayStr.append("困難程度 : \n");
                    displayStr.append("\t"+difficultSpinnerHandler.getSpinnerValue()+"\n");
                    String spinnerValue = difficultSpinnerHandler.getSpinnerValue();
                    int index = SudokuGameInfoParam.getDifficultyLevelIndexInChin(spinnerValue);
                    Controller.setDifficulty( DIFFICULTY_LEVEL[index]);
                    displayStr.append("規則優先 :\n");
                    for (int i=0; i<logicalRulesPrioritySpinnerHandler.length; i++){
                        displayStr.append("\t" + Integer.toString(i+1) +".");
                        displayStr.append(logicalRulesPrioritySpinnerHandler[i].getSpinnerValue()+"\n");
                        spinnerValue = logicalRulesPrioritySpinnerHandler[i].getSpinnerValue();
                        index = SudokuGameInfoParam.getLogicalRulesIndexInChin(spinnerValue);
                        Controller.setRulesPriority(LOGICAL_RULES[index], i);
                    }
                    displayStr.append(HINTS_PANEL_SEPARATOR);
                }
                
                Controller.setTextLearnerStepsMsgBox(displayStr.toString());

                /*UI onButtonPressed Step 8 : set solving status */
                Controller.setTextSolvingStatus(Controller.getNumCellsUnsolved());

                /* TUTOR onButtonPressed Step 1 : setup tutorModel with solved puzzle */
                Controller.setupStepsMatrix(Controller.applyLogicalRules());
                Controller.setupHintsGenerator(Controller.solvePuzzle());

                // 20091029 phrase2 start
                Controller.reocrdStepsMatrix(Controller.getCorrectStepsCount());
                // 20091029 phrase2 end

                /* TUTOR onButtonPressed Step 2 : Set Rules Ranking */
                this.setRulesRanking();
                /* TUTOR onButtonPressed Step 3 : setup current breadthSteps */
                // 20091019 phrase2 start
                //Controller.setupStepsMatrix(Controller.applyLogicalRules());
                // 20091019 phrase2 end

                /* TUTOR onButtonPressed Step 4 : setup autoHintsGiving */
                // 20091112 phrase2 start
                /* set hints giving with 0 - lowest level */

                Controller.reStartAutoHintsTimer(-1);
                // 20091112 phrase2 end
            }
            else{
                alertGameNotAvailable();
            }
        }
        else{
            alertDuplicateRulesPriority();
        }
    }
    /* for Sudoku UI */
    public void setGameboard(int[] inputGivenCells, int[][] inputDefiniteNum){
        final int[] givenCells = inputGivenCells;
        final int[][] DefiniteNum = inputDefiniteNum;
        /* Gameboard settings 1 : set the given cells */
        Gameboard.setGivenCells(givenCells);
        /* Gameboard settings 2 : set the poss values to cells */
        for(int i=0; i <  DefiniteNum.length; i++){
            /* +1 add as the cell value from 1-9 */
            Gameboard.setDefiniteCellsValue( DefiniteNum[i], i+1);
        }

        // to be improve ...
        isCalcMode = SudokuComponentsProperties.getIsTrue();
        this.refreshGameboard();
    }
    public void setButtonDisableAfterStart(){
        startGameButton.setEnabled(SudokuComponentsProperties.getIsFalse());
        difficultSpinnerHandler.setSpinnerEnabled(SudokuComponentsProperties.getIsFalse());
        for (int i=0; i<logicalRulesPriority.length; i++){
            logicalRulesPrioritySpinnerHandler[i].setSpinnerEnabled(SudokuComponentsProperties.getIsFalse());
        }
    }
    public boolean checkInputSetting(){

        /* int[i] - > i=rulesNumber, int[i]=priority of rules */
        int[] rulesPriority = new int[SudokuGameInfoParam.getLogicalRules().length];
        Boolean isSettingsCorrect = true;

        /* initialize the variables*/
        for (int i=0; i<rulesPriority.length; i++){
            rulesPriority[i]=-1;
        }

        for(int i=0; i< logicalRulesPriority.length; i++){
             for(int j=0; j< LOGICAL_RULES.length; j++){
                 String spinnerValue = logicalRulesPrioritySpinnerHandler[i].getSpinnerValue();
                 if(LangMode == CHIN_MODE){
                    int index = SudokuGameInfoParam.getLogicalRulesIndexInChin(spinnerValue);
                    spinnerValue = LOGICAL_RULES[index];
                 }

                 if( LOGICAL_RULES[j].equalsIgnoreCase(spinnerValue)){
                     if (rulesPriority[j] < 0){
                        rulesPriority[j]=i;
                        break;
                     }else{
                         isSettingsCorrect=false;
                     }
                 }
             }
        }
        return isSettingsCorrect;
    }
    public void alertGameNotAvailable(){
        if (LangMode == ENG_MODE){
            OptionTitle = AlertBoxParam.getGameNotAvailableAlertTitle();
            OptionMsg = AlertBoxParam.getGameNotAvailableAlertMsg();
        }
        if (LangMode == CHIN_MODE){
            OptionTitle = AlertBoxParam.getGameNotAvailableAlertTitleInChin();
            OptionMsg = AlertBoxParam.getGameNotAvailableAlertMsgInChin();
        }
        PlayerReply=JOptionPane.showConfirmDialog(null, OptionMsg, OptionTitle, JOptionPane.YES_OPTION);
    }
    public void alertDuplicateRulesPriority(){
        if (LangMode == ENG_MODE){
            OptionTitle = AlertBoxParam.getDuplicateRulesPriorityAlertTitle();
            OptionMsg = AlertBoxParam.getDuplicateRulesPriorityAlertMsg();
        }
        if (LangMode == CHIN_MODE){
            OptionTitle = AlertBoxParam.getDuplicateRulesPriorityAlertTitleInChin();
            OptionMsg = AlertBoxParam.getDuplicateRulesPriorityAlertMsgInChin();
        }
        PlayerReply=JOptionPane.showConfirmDialog(null, OptionMsg, OptionTitle, JOptionPane.YES_OPTION);
    }
    /* This function only shows the Sudoku UI */
    public void refreshGameboard(){

        /* below settings situate in other place start */
        boolean isCalcCellVisible = SudokuComponentsProperties.getIsFalse();
        boolean isDefiniteCell = SudokuComponentsProperties.getIsFalse();
        boolean isGiven = SudokuComponentsProperties.getIsFalse();
        /* below settings situate in other place end */
        int cellValue;
        
        for(int i=0; i<cellsContainersPane.length; i++){
            for(int j=0; j<cellsContainersPane[i].length; j++){
                /* Step 1 : show and set cell value */
                /* for user interface */
                isGiven = Gameboard.isGivenCells(i, j);

                if(isGiven){
                    /* step 2 : set display value to definite value */
                    cellValue = Gameboard.getDefiniteCellValue(i, j);
                    /* step 3 : set given cells style */
                    cellsContainersPane[i][j].setBackground(SudokuComponentsProperties.getColorGivenCellValueBackGround());
                    cellsValueLabel[i][j].setForeground(SudokuComponentsProperties.getColorGivenCellValueForeGround());
                    /* step 4 : disable DND function perform on given cells*/
                    DnD.isDropTargetEnabled(i, j, SudokuComponentsProperties.getIsFalse());
                }else{
                    cellValue = Gameboard.getCellValue(i, j);
                }

                /* 0 is default cell value */
                if(cellValue!=0){
                    Controller.setTextCellsValueLabel(i, j, cellValue);
                    //cellsValueLabel[i][j].setText(Integer.toString(cellValue));
                    isDefiniteCell = SudokuComponentsProperties.getIsTrue();
                }else{
                    Controller.setTextCellsValueLabel(i, j, cellValue);
                    //cellsValueLabel[i][j].setText("");
                    isDefiniteCell = SudokuComponentsProperties.getIsFalse();
                }

                /* Step 5 : show calculation cells */
                for(int k=0; k<caluCellsLabel[i][j].length; k++){
                   isCalcCellVisible = isCalcMode && Gameboard.isPossCellValue(i, j, k+1) && !isDefiniteCell;
                   //caluCellsLabel[i][j][k].setVisible(isCalcCellVisible);
                   Controller.setVisibleCaluCellsLabel(i, j, k, isCalcCellVisible);
                }
               
            }
        }
    }
    public Hashtable getGamePuzzles(){
        String difficultyValue = difficultSpinnerHandler.getSpinnerValue();
        if(LangMode == CHIN_MODE){
            int index = SudokuGameInfoParam.getDifficultyLevelIndexInChin(difficultyValue);
            difficultyValue = DIFFICULTY_LEVEL[index];
        }
        final int difficultyIndex = SudokuGameInfoParam.getDifficultyLevelIndex(difficultyValue);
        final Integer[] difficultyRange = Controller.getDifficultyRange(difficultyIndex);
        final int minNumber = difficultyRange[MIN_DIFFICULTY_INDEX];
        final int maxNumber = difficultyRange[MAX_DIFFICULTY_INDEX];
        /* Step 1 : get game puzzles with learner's request difficulty */
        Hashtable resultTable=dbManager.getGamePuzzles(minNumber, maxNumber);
        /* Step 2 : set game difficulty for expert model */
        Controller.setDifficultyLevel(difficultyValue);
        return resultTable;
    }


    public void setRulesRanking(){
        /* organize rules ranking list */
        ArrayList<Integer> rulesRanking = new ArrayList<Integer>();
        for (int i=0; i < logicalRulesPriority.length; i++){
            String logicalRulesValue = logicalRulesPrioritySpinnerHandler[i].getSpinnerValue();
            if(LangMode == CHIN_MODE){
                int index = SudokuGameInfoParam.getLogicalRulesIndexInChin(logicalRulesValue);
                logicalRulesValue = LOGICAL_RULES[index];
            }
            final int rulesIndex = SudokuGameInfoParam.getLogicalRulesIndex(logicalRulesValue);
            rulesRanking.add(rulesIndex);
        }
        /* setup expertModel */
        Controller.setRulesRanking(rulesRanking);
    }
    /* start button action perform end**********************************************************************/
    /* setup GameInfoPanel UI component end ***********************************************************************************************/

    /* setup HintsPanel UI component start ******************************************************************************************************/
    public void setupHintsPanelUI(){
        /* UI component 1 : setup activities box */
        learnerStepsMsgBox = new JTextArea();
        learnerStepsMsgBox.setBackground(SudokuComponentsProperties.getColorHintsBox());
        learnerStepsMsgBox.setFont(SudokuComponentsProperties.getFontHintsBox());
        learnerStepsMsgBox.setEditable(SudokuComponentsProperties.getIsFalse());

        JScrollPane hintsBoxScrollPane = new JScrollPane(learnerStepsMsgBox);
        /* Only set the vertical bar */
        hintsBoxScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        hintsBoxScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        hintsBoxScrollPane.setBounds(HINTS_BOX_POSX, HINTS_BOX_POSY, WSIZE_HINTS_BOX, LSIZE_HINTS_BOX);
        /* empty the boder of scrollpane*/
        hintsBoxScrollPane.setBorder(BorderFactory.createEmptyBorder());
        HintsPanel.add(hintsBoxScrollPane);
    }
    /* setup HintsPanel UI component end ******************************************************************************************************/

    /* setup ITS Models start***************************************************************************************************/
    public void setupITSModels(){

        /* Set up Gameboard */
        Gameboard = new SudokuGameboard();

        /* Set up ControlLayer */
        Controller = new ControlLayer(this, caluCellsLabel, cellsValueLabel, learnerStepsMsgBox,
        SolvingStatus, GameStatus, HintsStatus, Timer, gameConclusionPane, Gameboard, LangMode);

        /* Interface Communication with 3 models */
        DnD = new DnDHandler(cellsValueLabel, caluCellsLabel, Gameboard, Controller, undoStepsButton, redoStepsButton);
        DnD.setupDnD(dndLabel, GameAreaPanel);
        /* disable all DnD function s before start */
        DnD.isDNDFunctionEnable(SudokuComponentsProperties.getIsFalse());

    }
    /* setup ITS Models end***************************************************************************************************/

    /* setup DB Manager start***************************************************************************************************/
    public void setupDBManager(){
        dbManager = new DatabaseManager(Controller);
        // 20091015 phrase2 start - comment
        //dbManager.connectDB();
        // 20091015 phrase2 end
    }
    /* setup DB Manager end***************************************************************************************************/

    /* setup model bridge start **********************************************************************************************/
    
    /* setup model bridge end *************************************************************************************************/

    /* Generated Code Start**********************************************************************************************************/
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        SudokuDesktopPane = new javax.swing.JDesktopPane();
        GameAreaPanel = new javax.swing.JLayeredPane();
        HintsPanel = new javax.swing.JPanel();
        GameInfoPanel = new javax.swing.JPanel();

        SudokuDesktopPane.setBackground(new java.awt.Color(255, 255, 255));
        SudokuDesktopPane.setMinimumSize(new java.awt.Dimension(800, 800));
        SudokuDesktopPane.setRequestFocusEnabled(false);

        GameAreaPanel.setBackground(new java.awt.Color(255, 255, 255));
        GameAreaPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(new javax.swing.border.LineBorder(new java.awt.Color(255, 51, 51), 1, true), "Game Area", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Arial", 0, 11), new java.awt.Color(255, 51, 51))); // NOI18N
        GameAreaPanel.setMinimumSize(new java.awt.Dimension(505, 505));

        javax.swing.GroupLayout GameAreaPanelLayout = new javax.swing.GroupLayout(GameAreaPanel);
        GameAreaPanel.setLayout(GameAreaPanelLayout);
        GameAreaPanelLayout.setHorizontalGroup(
            GameAreaPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 495, Short.MAX_VALUE)
        );
        GameAreaPanelLayout.setVerticalGroup(
            GameAreaPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 541, Short.MAX_VALUE)
        );

        GameAreaPanel.setBounds(5, 5, 505, 560);
        SudokuDesktopPane.add(GameAreaPanel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        HintsPanel.setBackground(new java.awt.Color(255, 255, 255));
        HintsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(new javax.swing.border.LineBorder(new java.awt.Color(255, 51, 51), 1, true), "Hints and Review Box", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Arial", 0, 11), new java.awt.Color(255, 51, 51))); // NOI18N
        HintsPanel.setMinimumSize(new java.awt.Dimension(505, 215));

        javax.swing.GroupLayout HintsPanelLayout = new javax.swing.GroupLayout(HintsPanel);
        HintsPanel.setLayout(HintsPanelLayout);
        HintsPanelLayout.setHorizontalGroup(
            HintsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 495, Short.MAX_VALUE)
        );
        HintsPanelLayout.setVerticalGroup(
            HintsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 201, Short.MAX_VALUE)
        );

        HintsPanel.setBounds(5, 570, 505, 225);
        SudokuDesktopPane.add(HintsPanel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        GameInfoPanel.setBackground(new java.awt.Color(255, 255, 255));
        GameInfoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(new javax.swing.border.LineBorder(new java.awt.Color(255, 51, 51), 1, true), "Game Information", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Arial", 0, 11), new java.awt.Color(255, 51, 51))); // NOI18N

        javax.swing.GroupLayout GameInfoPanelLayout = new javax.swing.GroupLayout(GameInfoPanel);
        GameInfoPanel.setLayout(GameInfoPanelLayout);
        GameInfoPanelLayout.setHorizontalGroup(
            GameInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 270, Short.MAX_VALUE)
        );
        GameInfoPanelLayout.setVerticalGroup(
            GameInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 156, Short.MAX_VALUE)
        );

        GameInfoPanel.setBounds(515, 5, 280, 790);
        SudokuDesktopPane.add(GameInfoPanel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(SudokuDesktopPane, javax.swing.GroupLayout.PREFERRED_SIZE, 800, javax.swing.GroupLayout.PREFERRED_SIZE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(SudokuDesktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
        );
    }// </editor-fold>

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new WebSudokuApplet().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private JLayeredPane GameAreaPanel;
    private JPanel GameInfoPanel;
    private JPanel HintsPanel;
    private JDesktopPane SudokuDesktopPane;
    private JLayeredPane BlockPane;
    // End of variables declaration
    /* Generated Code End**************************************************************************************************************/

    /* Component for Game Area Panel UI */
    /* determine the position of cell */
    private JLabel[][] determinePosLabel ;
    /* draw the box border*/
    private JLabel[][] boxBorderLabel ;
    /* contain the cell label pane */
    private JLayeredPane[][] cellsContainersPane ;
    /* cell label */
    private JLabel[][] cellsValueLabel ;
    /* calculation cell label for user convenience */
    private JLabel[][][] caluCellsLabel ;

    /* determine the mouse contril label*/
    private JLabel controlLabel ;
    /* DnD input label determine the input values*/
    private JLabel[] dndLabel ;

    /* Component for Game Info Panel UI */
    /* Spinners */
    JSpinner difficultSpinner;
    JSpinner[] logicalRulesPriority;
    /* SpinnerHandler */
    SpinnerHandler[] logicalRulesPrioritySpinnerHandler;
    SpinnerHandler difficultSpinnerHandler;
    /* Start Button */
    private JButton startGameButton ;
    /* Timer */
    private TimerHandler Timer;
    private JButton TimerControlButton;
    /* Solving Status */
    private JLabel SolvingStatus;
    /* Hints Status */
    private JLabel[] HintsStatus;
    private int[] NumHintsGivenOn;
    private JButton[] HintsRequestButton;
    /* Game Status */
    private JLabel GameStatus;
    /* Seperator - to seperate game info channel and settings */
    private JSeparator settingSeparator;
    /* check boxes */
    private JCheckBox caluCellsCheckBox;
    private JCheckBox autoHintsCheckBox;
    /* Steps management button */
    private JButton redoStepsButton ;
    private JButton undoStepsButton ;

    /* Component for Hints Panel UI */
    private JTextArea learnerStepsMsgBox;

    private DnDHandler DnD;
    public DropTargetListener dropTargetListener;

    private int UserID;
    //20100112
    /* 0: Chinese, 1:English*/
    private int LangMode;

    /* ITS Models*/
    /*
    private ExpertModel expertModel;
    private TutorModel tutorModel;
    private StudentModel studentModel;
     */
    private ControlLayer Controller;

    /* Sudoku gameboard */
    SudokuGameboard Gameboard;
    /* Data Handler*/
    private DatabaseManager dbManager;
    /* applet input parameter */
    /* Alert box variables for checking action perform*/
    private int PlayerReply;
    private String OptionTitle;
    private String OptionMsg;

    /* store if using calc mode - default as true */
    private boolean isCalcMode;

    // 20091112 phrase2 start
    private boolean isAutoHintsMode;
    // 20091112 phrase2 end

    /* store if click calu cells is enable - default as false */
    private boolean isClickCaluCell;

    private JPanel gameConclusionPane;
    
    /* Common Variables */
    /* From BasicSudokuParam*/
    final int NUM_CELL_VALUE = BasicSudokuParam.getNumCellValue();
    final int NUM_CELL_IN_UNIT = BasicSudokuParam.getNumCellsInUnit();
    final int NUM_CELLS_IN_UNIT = BasicSudokuParam.getNumCellsInUnit();
    final int BOX_LENGTH_IN_CELLS = BasicSudokuParam.getBoxLengthInCells();
    /* From SudokuComponenetsProperties */
    final int SIZE_CELL = SudokuComponentsProperties.getSizeCell();
    final int GAME_START_POS=SudokuComponentsProperties.getGameStartPos();
    final int SIZE_DETERMINE_POS = SudokuComponentsProperties.getSizeDeterminePos();
    final int CELL_START_POS = SudokuComponentsProperties.getCellStartPos();
    final int SIZE_CALU_CELL = SudokuComponentsProperties.getSizeCaluCell();
    final int SIZE_BOX=SudokuComponentsProperties.getSizeBox();
    final int START_LABEL_POSX = SudokuComponentsProperties.getStartLabelPosX();
    final int START_LABEL_POSY = SudokuComponentsProperties.getStartLabelPosY();
    final int LSIZE = SudokuComponentsProperties.getLSize();
    final int WSIZE_SPINNER = SudokuComponentsProperties.getWSizeSpinner();
    final int WSIZE_BULLET = SudokuComponentsProperties.getWSizeBullet();
    final int WSIZE_STATIC_LABEL = SudokuComponentsProperties.getWSizeStaticLabel();
    final int WSIZE_VARIABLE = SudokuComponentsProperties.getWSizeVariable();
    final int LSIZE_VARIABLE = SudokuComponentsProperties.getLSizeVariable();
    final int ITEMS_SEPERATOR_SPACING = SudokuComponentsProperties.getItemSeperatorSpacing();
    final int SPINNER_SPACING = SudokuComponentsProperties.getSpinnersSpacing();
    final int START_BUTTON_POSX = SudokuComponentsProperties.getStartButtonPosX();
    final int START_BUTTON_POSY = SudokuComponentsProperties.getStartButtonPosY();
    final int WSIZE_BUTTON = SudokuComponentsProperties.getWSizeButton();
    final int LSIZE_BUTTON = SudokuComponentsProperties.getLSizeButton();
    final int TIMER_LABEL_POS_X = SudokuComponentsProperties.getTimerLabelPosX();
    final int TIMER_LABEL_POS_Y = SudokuComponentsProperties.getTimerLabelPosY();
    final int SOLVING_STATUS_LABEL_POSX = SudokuComponentsProperties.getSolvingStatusLabelPosX();
    final int SOLVING_STATUS_LABEL_POSY = SudokuComponentsProperties.getSolvingStatusLabelPosY();
    final int GAME_STATUS_LABEL_POSX = SudokuComponentsProperties.getGameStatusLabelPosX();
    final int GAME_STATUS_LABEL_POSY = SudokuComponentsProperties.getGameStatusLabelPosY();
    final int STEPS_MANAGE_BUTTON_POSX = SudokuComponentsProperties.getStepsManageButtonPosX();
    final int STEPS_MANAGE_BUTTON_POSY = SudokuComponentsProperties.getStepsManageButtonPosY();
    final int ITEM_SEPERATOR_SPACING = SudokuComponentsProperties.getItemSeperatorSpacing();
    final int HINTS_STATUS_LABEL_POSX = SudokuComponentsProperties.getHintsStatusPosX();
    final int HINTS_STATUS_LABEL_POSY = SudokuComponentsProperties.getHintsStatusPosY();
    final int LSIZE_SEPARATOR = SudokuComponentsProperties.getLSizeSeparator();
    final int WSIZE_SEPARATOR = SudokuComponentsProperties.getWSizeSeparator();
    final int SEPARATOR_POSX = SudokuComponentsProperties.getSeparatorPosX();
    final int SEPARATOR_POSY = SudokuComponentsProperties.getSeparatorPosY();
    final int CALU_CELLS_CLICK_POSX = SudokuComponentsProperties.getCaluCellsClickPosX();
    final int CALU_CELLS_CLICK_POSY = SudokuComponentsProperties.getCaluCellsClickPosY();
    final int AUTO_HINTS_CLICK_POSX = SudokuComponentsProperties.getAutoHintsClickPosX();
    final int AUTO_HINTS_CLICK_POSY = SudokuComponentsProperties.getAutoHintsClickPosY();
    final int WSIZE_HINTS_BOX = SudokuComponentsProperties.getWSizeHintsBox();
    final int LSIZE_HINTS_BOX = SudokuComponentsProperties.getLSizeHintsBox();
    final int HINTS_BOX_POSX = SudokuComponentsProperties.getHintsBoxPosX();
    final int HINTS_BOX_POSY = SudokuComponentsProperties.getHintsBoxPosY();
    final String HINTS_PANEL_SEPARATOR = SudokuComponentsProperties.getHintsPanelSeparator();
    final int DIFFICULTY_POSX = SudokuComponentsProperties.getDifficultyPosX();
    final int DIFFICULTY_POSY = SudokuComponentsProperties.getDifficultyPosY();
    final int PRIORITY_POSX = SudokuComponentsProperties.getPriorityPosX();
    final int PRIORITY_POSY = SudokuComponentsProperties.getPriorityPosY();
    final int WSIZE_HINTS_LABEL = SudokuComponentsProperties.getWSizeHintsLabel();
    final int WSIZE_HINTS_VARIABLE = SudokuComponentsProperties.getWSizeHintsVariable();
    /* From SudokuGameInfoParam */
    final String[] LOGICAL_RULES = SudokuGameInfoParam.getLogicalRules();
    final int MIN_DIFFICULTY_INDEX = SudokuGameInfoParam.getMinDifficultyIndex();
    final int MAX_DIFFICULTY_INDEX = SudokuGameInfoParam.getMaxDifficultyIndex();
    final String[] DIFFICULTY_LEVEL = SudokuGameInfoParam.getDifficultyLevels();
    final String[] HINTS_LEVEL = SudokuGameInfoParam.getHintsLevel();
    final String GAME_STATUS_CORRECT = SudokuGameInfoParam.getGameStatusCorrrect();
    final String GAME_STATUS_WRONG = SudokuGameInfoParam.getGameStatusWrong();
    final String[] LOGICAL_RULES_IN_CHIN = SudokuGameInfoParam.getLogicalRulesInChin();
    final String[] HINTS_LEVEL_IN_CHIN = SudokuGameInfoParam.getHintsLevelInChin();
    final String GAME_STATUS_CORRECT_IN_CHIN = SudokuGameInfoParam.getGameStatusCorrrectInChin();
    final String GAME_STATUS_WRONG_IN_CHIN = SudokuGameInfoParam.getGameStatusWrongInChin();
    final int ENG_MODE = SudokuGameInfoParam.getEnglishMode();
    final int CHIN_MODE = SudokuGameInfoParam.getChineseMode();
    /* From StudentModelDiagonsisProperties */
    final String ERASE_VALUE_COMMAND = StudentModelProperties.getEraseValueCommand();
    final String ASSIGN_VALUE_COMMAND = StudentModelProperties.getAssignValueCommand();
    final String POSSIBLE_CALU_VALUE_COMMAND = StudentModelProperties.getPossibleCaluValueCommand();
    final String IMPOSSIBLE_CALU_VALUE_COMMAND = StudentModelProperties.getImpossibleCaluValueCommand();
}
